/*
 * Class: TimeSpan
 * License: BSD
 * Author: Lucifer Xu(colorful1982@gmail.com)
 * Date: 2007-05-14
 * Purpose: TimeSpan represents a duration of time. A TimeSpan can be negative or postive and is internally represented as a number of milliseconds.
 */

//貌似与 dotmars.base.time.TimeSpan 重复


module dotmars.diagnostics.timespan;

/+
import  dotmars.base.stdexcept;
/*
 * 表示一个时间间隔，可正可负。
 * TimeSpan在其内部表示成毫秒数。
 * 开发人员应当将其表示成更加可观的数字表示。
 * 因为并不清楚dotmars的设计原则，暂时没有接口实现。
 */
public final class TimeSpan
{
    /* 表示 1 毫秒的刻度数 */
    public const long TicksPerMillisecond = 10000;
    private const double MillisecondsPerTick = 1.0 / TicksPerMillisecond;
    /* 表示 1 秒的刻度数 */
    public const long TicksPerSecond = TicksPerMillisecond * 1000;
    private const double SecondsPerTick = 1.0 / TicksPerSecond;
    /* 表示 1 分钟的刻度数 */
    public const long TicksPerMinute = TicksPerSecond * 60;
    private const double MinutesPerTick = 1.0 / TicksPerMinute;
    /* 表示 1 小时的刻度数 */
    public const long TicksPerHour = TicksPerMinute * 60;
    private const double HoursPerTick = 1.0 / TicksPerHour;
    /* 表示一天中的刻度数 */
    public const long TicksPerDay = TicksPerHour * 24;
    private const double DaysPerTick = 1.0 / TicksPerDay;

    private const int MillisPerSecond = 1000;
    private const int MillisPerMinute = MillisPerSecond * 60;
    private const int MillisPerHour = MillisPerMinute * 60;
    private const int MillisPerDay = MillisPerHour * 24;

    private const long MaxSeconds = long.max / TicksPerSecond;
    private const long MinSeconds = long.min / TicksPerSecond;

    private const long MaxMilliseconds = long.max / TicksPerMillisecond;
    private const long MinMilliseconds = long.min / TicksPerMillisecond;
    /* 表示零 TimeSpan 值 */
    /* 这里采用取巧的 Singleton 办法，且线程安全，这是由D编译器来保证的 */
    private static TimeSpan zero;
    public static TimeSpan Zero(){return zero;};
    /* 表示最大的 TimeSpan 值 */
    private static TimeSpan maxValue;
    public static TimeSpan MaxValue()
    {
        return maxValue;
    }
    /* 表示最小的 TimeSpan 值 */
    private static TimeSpan minValue;
    public static TimeSpan MinValue()
    {
        return minValue;
    }

    public static this()
    {
        zero = new TimeSpan(0);
        maxValue = new TimeSpan(long.max);
        minValue = new TimeSpan(long.min);
    }
    /* 获取表示当前 TimeSpan 结构的值的刻度数 */
    package long ticks;
    public long Ticks() {return ticks;}
    public this(long ticks)
    {
        this.ticks = ticks;
    }
    public this(int hours, int minutes, int seconds)
    {
        this.ticks = TimeToTicks(hours, minutes, seconds);
    }
    public this(int days, int hours, int minutes, int seconds, int milliseconds)
    {
        long totalMilliseconds =( (cast(long)days * 3600 * 24) + (cast(long)hours * 3600) + (cast(long)minutes * 60) + (cast(long)seconds) ) * 1000 + cast(long)milliseconds;
        if(totalMilliseconds > MaxMilliseconds || totalMilliseconds < MinMilliseconds)
        {
            throw new ArgumentOutOfRangeException("TimeSpanTooLong.");
        }
        this.ticks = totalMilliseconds * TicksPerMillisecond;
    }
    /* 获取由当前 TimeSpan 结构表示的整天数 */
    public int Days()
    {
        return cast(int)(ticks / TicksPerDay);
    }
    /* 获取由当前 TimeSpan 结构表示的整小时数 */
    public int Hours()
    {
        return cast(int)((ticks / TicksPerHour) % 24);
    }
    /* 获取由当前 TimeSpan 结构表示的整分钟数 */
    public int Minutes()
    {
        return cast(int)((ticks / TicksPerMinute) % 60);
    }
    /* 获取由当前 TimeSpan 结构表示的整毫秒数 */
    public int Milliseconds()
    {
        return cast(int)((ticks / TicksPerMillisecond) % 1000);
    }
    /* 获取由当前 TimeSpan 结构表示的整秒数 */
    public int Seconds()
    {
        return cast(int)((ticks / TicksPerSecond) % 60);
    }
    /* 获取以整天数和天的小数部分表示的当前 TimeSpan 结构的值 */
    public double TotalDays()
    {
        return (cast(double)ticks) * DaysPerTick;
    }
    /* 获取以整小时数和小时的小数部分表示的当前 TimeSpan 结构的值 */
    public double TotalHours()
    {
        return (cast(double)ticks) * HoursPerTick;
    }
    /* 获取以整分钟数和分钟的小数部分表示的当前 TimeSpan 结构的值 */
    public double TotalMinutes()
    {
        return (cast(double)ticks) * MinutesPerTick;
    }
    /* 获取以整毫秒数和毫秒的小数部分表示的当前 TimeSpan 结构的值 */
    public double TotalMilliseconds()
    {
        double temp = (cast(double)ticks) * MillisecondsPerTick;
        if(temp > MaxMilliseconds)
        {
            return cast(double)MaxMilliseconds;
        }
        if(temp < MinMilliseconds)
        {
            return cast(double)MinMilliseconds;
        }
        return temp;
    }
    /* 获取以整秒数和秒的小数部分表示的当前 TimeSpan 结构的值 */
    public double TotalSeconds()
    {
        return (cast(double)ticks) * SecondsPerTick;
    }

    /* 返回新的 TimeSpan 对象，其值是当前 TimeSpan 对象的绝对值 */
    public TimeSpan Duration()
    {
        if(ticks == TimeSpan.minValue.Ticks)
        {
            throw new OverflowException("DurationOverflow.");
        }
        return new TimeSpan(ticks >= 0 ? ticks : -ticks);
    }
    /* 返回其值为此实例的相反值的 TimeSpan */
    public TimeSpan Negate()
    {
        if(ticks == TimeSpan.minValue.Ticks)
        {
            throw new OverflowException("DurationOverflow.");
        }
        return new TimeSpan(-ticks);
    }

    /* 将指定的 TimeSpan 添加到此实例中 */
    public TimeSpan Add(TimeSpan timeSpan)
    {
        long result = this.ticks + timeSpan.Ticks;
        // Overflow if signs of operands was identical and result's sign was opposite.
        // >> 63 gives the sign bit (either 64 1's or 64 0's).
        if((this.ticks >> 63 == timeSpan.Ticks >> 63) && (this.ticks >> 63 != result >> 63))
        {
            throw new OverflowException("TimeSpanTooLong.");
        }
        return new TimeSpan(result);
    }
    /* 从此实例中减去指定的 TimeSpan */
    public TimeSpan Subtract(TimeSpan timeSpan)
    {
        long result = this.ticks - timeSpan.Ticks;
        // Overflow if signs of operands was identical and result's sign was opposite.
        // >> 63 gives the sign bit (either 64 1's or 64 0's).
        if((this.ticks >> 63 == timeSpan.Ticks >> 63) && (this.ticks >> 63 != result >> 63))
        {
            throw new OverflowException("TimeSpanTooLong.");
        }
        return new TimeSpan(result);
    }

    /* 返回表示指定天数的 TimeSpan，其中对天数的指定精确到最接近的毫秒 */
    public static TimeSpan FromDays(double value)
    {
        return Interval(value, MillisPerDay);
    }
    /* 返回表示指定小时数的 TimeSpan，其中对小时数的指定精确到最接近的毫秒 */
    public static TimeSpan FromHours(double value)
    {
        return Interval(value, MillisPerHour);
    }
    /* 返回表示指定分钟数的 TimeSpan，其中对分钟数的指定精确到最接近的毫秒 */
    public static TimeSpan FromMinutes(double value)
    {
        return Interval(value, MillisPerMinute);
    }
    /* 返回表示指定毫秒数的 TimeSpan */
    public static TimeSpan FromMilliseconds(double value)
    {
        return Interval(value, 1);
    }
    /* 返回表示指定秒数的 TimeSpan，其中对秒数的指定精确到最接近的毫秒 */
    public static TimeSpan FromSeconds(double value)
    {
        return Interval(value, MillisPerSecond);
    }
    /* 返回表示指定时间的 TimeSpan，其中对时间的指定以刻度为单位 */
    public static TimeSpan FromTicks(long value)
    {
        return new TimeSpan(value);
    }

    public override char[] toString()
    {
        throw new NotImplementation("NotImplementation.");
    }

    public override hash_t toHash()
    {
        /* 还有待验证 */
        return cast(hash_t)((cast(int)ticks) ^ (cast(int)ticks >> 32));

    }
    public override int opCmp(Object value)
    {
        if(value is null)
        {throw new ArgumentException("ArgumentCannotBeNull.");};
        if(!(is (typeof(value) == TimeSpan)))
        {
            throw new ArgumentException("ArgumentMustBeTimeSpan.");
        }
        long tempTicks = (cast(TimeSpan)value).Ticks;
        if(this.ticks > tempTicks) return 1;
        if(this.ticks < tempTicks) return -1;
        return 0;
    }
    public int opCmp(TimeSpan value)
    {
        if(value is null)
        {throw new ArgumentException("ArgumentCannotBeNull.");};
        if(this.ticks > value.Ticks) return 1;
        if(this.ticks < value.Ticks) return -1;
        return 0;
    }
    public override int opEquals(Object value)
    {
        if(value is null) throw new ArgumentException("CannotBeNull.");
        if(!(is (typeof(value) == TimeSpan)))
        {
            throw new ArgumentException("ArgumentMustBeTimeSpan.");
        }
        if(ticks == (cast(TimeSpan)value).Ticks)
        {
            return 0;
        }
        else
        {
            return cast(int)(this !is value);
        }
    }
    public bool opEquals(TimeSpan value)
    {
        if(value is null) return false;
        return (this.ticks == value.Ticks);
    }

    public TimeSpan opNeg()
    {
        TimeSpan temp = new TimeSpan(-ticks);
        if(temp.Ticks == TimeSpan.MinValue.Ticks)
        {
            throw new OverflowException("NegateTimeSpanOverflow.");
        }
        return temp;
    }

    public TimeSpan opPos()
    {
        return this;
    }

    public TimeSpan opAdd(TimeSpan timeSpan)
    {
        return this.Add(timeSpan);
    }

    public TimeSpan opSub(TimeSpan timeSpan)
    {
        return this.Subtract(timeSpan);
    }

    package static long TimeToTicks(int hours, int minutes, int seconds)
    {
        // totalSeconds边界是2^31*2^12+2^31*2^8+2^31，它小于2^44
        // 也就是说我们不必担心它会溢出
        long totalSeconds = (cast(long)hours * 3600) + (cast(long)minutes * 60) + (cast(long)seconds);
        if(totalSeconds > MaxSeconds || totalSeconds < MinSeconds)
        {
            throw new ArgumentOutOfRangeException("TimeSpanTooLong.");
        }
        return totalSeconds * TicksPerSecond;
    }
    private static TimeSpan Interval(double value, int scale)
    {
        if(value == double.nan)
        {
            throw new ArgumentException("ArgumentCannotBeNaN.");
        }
        double temp = value * scale;
        double millis = temp + (value >= 0 ? 0.5 : -0.5);
        if((millis > long.max / TicksPerMillisecond) || (millis < long.min / TicksPerMillisecond))
        {
            throw new OverflowException("TimeSpanTooLong.");
        }
        return new TimeSpan(cast(long)millis * TicksPerMillisecond);
    }
}
unittest
{
    TimeSpan a = new TimeSpan(0);
    TimeSapn b = new TimeSpan(10);
    TimeSpan c = new TimeSpan(10);
    TimeSpan d = new TimeSpan(20);
    Object e = new Object();
    assert(a==TimeSpan.Zero);
    assert(b==c);
    assert(b<d);
    assert(d>c);
    assert((b+c) == d);
    assert((b-c) == a);
    assert((b+(-c)) == a);
    assert(b==e);
    assert(b!=e);
}

+/
